import pandas as pd
import os
import json

class FinancialDataProcessor:
    """
    财务数据处理类
    负责按照自定义科目分类处理财务数据
    """
    def __init__(self, mapping_file=None):
        # 如果提供了映射文件，则从文件加载映射关系
        if mapping_file and os.path.exists(mapping_file):
            self.category_mapping = self._load_mapping_from_file(mapping_file)
        else:
            # 否则使用默认的映射关系（基于笔记.md）
            self.category_mapping = self._get_default_mapping()
    
    def _load_mapping_from_file(self, file_path):
        """
        从文件加载科目映射关系
        
        参数:
            file_path (str): 映射文件路径
            
        返回:
            dict: 科目映射关系
        """
        with open(file_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    
    def _get_default_mapping(self):
        """
        获取默认的科目映射关系（基于笔记.md）
        
        返回:
            dict: 科目映射关系
        """
        # 从config.mapping导入最新的映射关系
        try:
            from config.mapping import CATEGORY_MAPPING
            print("成功从config.mapping导入CATEGORY_MAPPING")
            return CATEGORY_MAPPING
        except ImportError:
            print("无法导入config.mapping，使用内置默认映射")
            # 基于笔记.md的自定义分类
            return {
                # 流动资产
                "现金类": {
                    "items": ["货币资金", "结算备付金", "拆出资金", "交易性金融资产", "衍生金融资产", "买入返售金融资产"],
                    "description": "即时支付能力",
                    "type": "流动资产",
                    "display_order": 1
                },
                "应收款类": {
                    "items": ["应收票据", "应收账款", "应收款项融资", "应收票据及应收账款"],
                    "description": "经营质量",
                    "type": "流动资产",
                    "display_order": 2
                },
                "预付款类": {
                    "items": ["预付款项"],
                    "description": "供应链地位",
                    "type": "流动资产",
                    "display_order": 3
                },
                "存货类": {
                    "items": ["存货"],
                    "description": "周转效率",
                    "type": "流动资产",
                    "display_order": 4
                },
                "其他流动类": {
                    "items": ["应收保费", "应收分保款项", "应收分保合同准备金", "其他应收款", "其他应收款(合计)", 
                            "应收利息", "应收股利", "应收出口退税", "应收补贴款", "应收保证金", "内部应收款",
                            "其他流动资产", "合同资产", "持有待售资产", "划分为持有待售的资产", "待摊费用", "待处理流动资产损益",
                            "一年内到期的非流动资产"],
                    "description": "异常项目",
                    "type": "流动资产",
                    "display_order": 5
                }
            }
    
    def categorize_data(self, raw_data):
        """
        按自定义分类整理数据
        
        参数:
            raw_data (pandas.DataFrame): 原始财务数据
            
        返回:
            pandas.DataFrame: 按自定义分类整理后的数据
        """
        if raw_data is None or raw_data.empty:
            return None
        
        # 打印原始数据的基本信息，帮助调试
        print(f"原始数据形状: {raw_data.shape}")
        print(f"原始数据列名: {raw_data.columns[:5]}...")
        print(f"原始数据索引: {raw_data.index[:5]}...")
        
        # 检查数据结构，判断是否为转置格式
        is_transposed = True  # 默认假设是转置格式（列为日期，行为科目）
        
        # 检查列名是否为日期格式
        date_format_columns = False
        if len(raw_data.columns) > 0:
            # 检查前几列是否为日期格式
            for col in raw_data.columns[:3]:  # 检查前3列
                col_str = str(col)
                # 日期格式可能是20210331或2021-03-31
                if col_str.replace('-', '').isdigit() and len(col_str.replace('-', '')) >= 8:
                    date_format_columns = True
                    break
            
            if not date_format_columns:
                # 如果列名不是日期格式，可能不是转置格式
                is_transposed = False
                print("检测到非转置格式数据（列名不是日期）")
        
        # 检查第一行是否包含科目名称
        subject_in_first_row = False
        if raw_data.shape[0] > 0:
            first_row_values = [str(val).strip() for val in raw_data.iloc[0].values]
            common_subjects = ["流动资产", "货币资金", "应收账款", "存货", "固定资产", "短期借款"]
            if any(subj in val for val in first_row_values for subj in common_subjects):
                subject_in_first_row = True
                is_transposed = False
                print("检测到非转置格式数据（第一行包含科目名称）")
        
        # 检查索引是否为科目名称
        subject_in_index = False
        if raw_data.index.dtype == 'object' and not raw_data.index.empty:
            # 检查索引的前几个值是否为科目名称
            sample_indices = [str(idx).strip() for idx in raw_data.index[:10].tolist()]
            common_subjects = ["流动资产", "货币资金", "应收账款", "存货", "固定资产", "短期借款"]
            if any(any(subj in idx for subj in common_subjects) for idx in sample_indices):
                subject_in_index = True
                is_transposed = True
                print("确认转置格式数据（索引为科目名称）")
        
        # 综合判断数据格式
        if subject_in_index:
            is_transposed = True
        elif subject_in_first_row or not date_format_columns:
            is_transposed = False
        
        print(f"数据格式判断: {'转置格式' if is_transposed else '非转置格式'}")
        
        # 获取最新日期列或行
        latest_date = None
        if is_transposed:
            # 如果是转置格式，尝试找到最新的日期列
            date_columns = []
            for col in raw_data.columns:
                col_str = str(col)
                # 尝试识别日期格式（20210331或2021-03-31）
                if col_str.replace('-', '').isdigit() and len(col_str.replace('-', '')) >= 8:
                    date_columns.append(col_str)
            
            if date_columns:
                # 按日期排序，选择最新的日期
                latest_date = sorted(date_columns)[-1]
                print(f"找到最新日期列: {latest_date}")
            elif len(raw_data.columns) > 0:
                # 如果没有找到日期列，使用第一列
                latest_date = str(raw_data.columns[0])
                print(f"未找到日期列，使用第一列: {latest_date}")
            else:
                # 如果没有列，使用当前日期
                from datetime import datetime
                latest_date = datetime.now().strftime('%Y%m%d')
                print(f"未找到有效列，使用当前日期: {latest_date}")
        else:
            # 如果是非转置格式，尝试从第一行获取日期
            if '报告日' in raw_data.columns:
                latest_date = str(raw_data.iloc[0]['报告日'])
                print(f"从'报告日'列获取日期: {latest_date}")
            elif '报告日期' in raw_data.columns:
                latest_date = str(raw_data.iloc[0]['报告日期'])
                print(f"从'报告日期'列获取日期: {latest_date}")
            else:
                # 如果没有找到日期列，使用当前日期
                from datetime import datetime
                latest_date = datetime.now().strftime('%Y%m%d')
                print(f"未找到日期列，使用当前日期: {latest_date}")
        
        # 添加报表日期列
        from datetime import datetime
        report_date = latest_date if latest_date else datetime.now().strftime('%Y%m%d')
        
        # 创建结果DataFrame，确保有一行数据
        result = pd.DataFrame(index=[0])
        result['报表日期'] = report_date
        
        # 按自定义分类整理数据
        for category, category_info in self.category_mapping.items():
            # 获取该分类下的科目列表
            if isinstance(category_info, dict):
                items = category_info.get('items', [])
            else:
                items = category_info  # 兼容旧版映射格式
            
            # 初始化该分类的总和为0.0
            result[category] = 0.0
            
            # 累加该分类下的所有科目
            for item in items:
                # 检查科目是否在原始数据中
                if is_transposed:
                    # 尝试精确匹配和部分匹配
                    matching_indices = [idx for idx in raw_data.index if str(idx).strip() == item]
                    if not matching_indices:
                        # 尝试部分匹配
                        matching_indices = [idx for idx in raw_data.index if item in str(idx).strip()]
                    
                    for idx in matching_indices:
                        try:
                            # 如果是转置格式，取最新日期的数据
                            if latest_date in raw_data.columns:
                                amount = raw_data.loc[idx, latest_date]
                                print(f"科目 {idx} 在 {latest_date} 的金额: {amount}")
                            elif len(raw_data.columns) > 0:
                                # 如果最新日期不在列中，取第一列数据
                                first_col = raw_data.columns[0]
                                amount = raw_data.loc[idx, first_col]
                                print(f"科目 {idx} 在 {first_col} 的金额: {amount}")
                            else:
                                print(f"警告: 科目 {idx} 没有可用的数据列")
                                continue
                            
                            # 如果金额是Series，取第一个值
                            if isinstance(amount, pd.Series):
                                amount = amount.iloc[0]
                            
                            # 转换为浮点数并处理NaN
                            try:
                                if pd.isna(amount) or amount == '':
                                    amount_float = 0.0
                                else:
                                    # 处理可能的字符串格式（如带逗号的数字）
                                    if isinstance(amount, str):
                                        amount = amount.replace(',', '')
                                    amount_float = float(amount)
                                    # 单位转换为亿元（假设原始数据单位为万元）
                                    amount_float = amount_float / 10000
                                    print(f"单位转换: {amount} 万元 -> {amount_float} 亿元")
                            except (ValueError, TypeError) as e:
                                print(f"警告: 无法将 {amount} 转换为浮点数，使用0代替: {e}")
                                amount_float = 0.0
                            
                            # 累加到对应分类
                            result.at[0, category] += amount_float
                            print(f"累加 {idx} 到 {category}: +{amount_float}, 当前总和: {result.at[0, category]}")
                        except Exception as e:
                            print(f"处理科目 {idx} 时出错: {e}")
                elif not is_transposed:
                    # 非转置格式处理逻辑（列为科目）
                    if item in raw_data.columns:
                        try:
                            # 取第一行的数据（最新数据）
                            amount = raw_data.iloc[0][item]
                            print(f"科目 {item} 的金额: {amount}")
                            
                            # 转换为浮点数并处理NaN
                            try:
                                if pd.isna(amount) or amount == '':
                                    amount_float = 0.0
                                else:
                                    # 处理可能的字符串格式（如带逗号的数字）
                                    if isinstance(amount, str):
                                        amount = amount.replace(',', '')
                                    amount_float = float(amount)
                                    # 单位转换为亿元（假设原始数据单位为万元）
                                    amount_float = amount_float / 10000
                                    print(f"单位转换: {amount} 万元 -> {amount_float} 亿元")
                            except (ValueError, TypeError) as e:
                                print(f"警告: 无法将 {amount} 转换为浮点数，使用0代替: {e}")
                                amount_float = 0.0
                            
                            # 累加到对应分类
                            result.at[0, category] += amount_float
                            print(f"累加 {item} 到 {category}: +{amount_float}, 当前总和: {result.at[0, category]}")
                        except Exception as e:
                            print(f"处理科目 {item} 时出错: {e}")
        
        # 检查结果是否有非零值
        non_zero_cols = [col for col in result.columns if col != '报表日期' and result[col].sum() > 0]
        if non_zero_cols:
            print(f"成功分类! 包含非零值的分类数量: {len(non_zero_cols)} / {len(result.columns) - 1}")
        else:
            print("警告: 分类后的数据全为零，请检查数据处理逻辑")
        
        return result
    
    def save_categorized_data(self, data, output_path):
        """
        保存分类后的数据
        
        参数:
            data (pandas.DataFrame): 分类后的数据
            output_path (str): 输出文件路径
        """
        if data is None or data.empty:
            print("没有数据可保存")
            return
        
        # 保存到CSV
        data.to_csv(output_path, encoding='utf-8-sig', index=False)
        print(f"分类数据已保存到: {output_path}")
    
    def save_mapping_to_file(self, file_path):
        """
        将科目映射关系保存到文件
        
        参数:
            file_path (str): 文件路径
        """
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(self.category_mapping, f, ensure_ascii=False, indent=4)
        print(f"科目映射关系已保存到: {file_path}")

# 测试代码
if __name__ == "__main__":
    processor = FinancialDataProcessor()
    # 保存默认映射关系到文件
    processor.save_mapping_to_file("../config/category_mapping.json")
    
    # 测试数据处理
    # 这里需要实际的数据才能测试
    # 可以先运行fetcher.py获取数据，然后在这里加载并处理